<?php
error_reporting ( 2047 );
class epoll {
    private static $socket;
    private static $connections = array ();
    private static $buffers = array ();
    private static $connection = null;
    private static $buffer = null;
    private static $id = 0;
    private static $ct_last;
    private static $pids = array ();
    /** 
     * 实例化
     */
    public function __construct($port, $num = 1, $process) {
        if ($port < 1024) {
            die ( "Port must be a number which bigger than 1024\n" );
        }
        self::$socket = stream_socket_server ( 'tcp://0.0.0.0:' . $port, $errno, $errstr );
        stream_set_blocking ( self::$socket, 0 );
        $base = event_base_new ();
        $event = event_new ();
        event_set ( $event, self::$socket, EV_READ | EV_PERSIST, 'epoll::ev_accept', $base );
        event_base_set ( $event, $base );
        event_add ( $event );
        self::sw_spawn ( $num );
        while ( true ) {
            event_base_loop ( $base, 0 );
            usleep ( 10 );
        }
    }
    /**
     * 接收请求
     */
    public static function ev_accept($socket, $flag, $base) {
        $connection = @stream_socket_accept ( $socket );
        if (! $connection) {
            return;
        }
        stream_set_blocking ( $connection, 0 );
        self::$id += 1;
        $buffer = event_buffer_new ( $connection, 'epoll::ev_read', NULL, 'epoll::ev_error', self::$id );
        event_buffer_base_set ( $buffer, $base );
        event_buffer_timeout_set ( $buffer, 3, 3 );
        event_buffer_watermark_set ( $buffer, EV_READ, 0, 0xffffff );
        event_buffer_priority_set ( $buffer, 10 );
        event_buffer_enable ( $buffer, EV_READ | EV_PERSIST );
        //保存请求 
        self::$connections [self::$id] = $connection;
        self::$buffers [self::$id] = $buffer;
    
    }
    /**
     * 客户端连接出错或退出
     */
    public static function ev_error($buffer, $error, $id) {
        event_buffer_disable ( self::$buffers [$id], EV_READ | EV_WRITE );
        event_buffer_free ( self::$buffers [$id] );
        fclose ( self::$connections [$id] );
        unset ( self::$buffers [$id], self::$connections [$id] );
        echo date ( "Y-m-d H:i:s" ) . ": client $id close total clients " . count ( self::$buffers ) . " \r\n";
    }
    /**
     * 读请求内容
     */
    public static function ev_read($buffer, $id) {
        $receiveBuffer = null;
        while ( @$read = event_buffer_read ( $buffer, 256 ) ) {
            $receiveBuffer .= $read;
        }
        self::apprun ( $receiveBuffer, $id );
    }
    public static function apprun($recdata, $id) {
        $thispage = '';
        if (preg_match ( '/(GET|POST)(.*)HTTP/', $recdata, $rec )) {
            $thispage = @$rec [2];
        }
        if ($thispage) { //普通的http短连接 GET请求
            $timestart = microtime ( true );
            $thispage = trim ( str_replace ( array ('/index.php/', '/index.php' ), 'index.php ', $thispage ) );
            if (substr ( trim ( $thispage ), 0, 1 ) == '/') {
                $thispage = substr ( $thispage, 1 );
            }
            if (! preg_match ( '/index.php/', $thispage )) {
                $thispage = 'index.php ' . $thispage;
            }
            echo $thispage . "\n";
            ob_start ();
            $content_grabbed = passthru ( "php $thispage", $out );
            $content_grabbed = ob_get_contents ();
            ob_end_clean ();
            $timeend = microtime ( true );
            $runtime = round ( ($timeend - $timestart) * 1000, 1 );
            $head = "HTTP/1.1 200 OK\r\n" . "Connection:Keep-Alive\r\n" . "Content-Length: " . strlen ( $content_grabbed . $runtime ) . "\r\n" . "Content-Type:text/html;charset=utf-8" . "\r\n\r\n";
            // echo $content_grabbed;            
            self::ev_send ( $id, $head . $content_grabbed . $runtime );
            self::close ( $id );
        } else { //TCP长连接
            self::ev_send ( $id, 'welcome!' );
        }
    
    }
    /**
     * 发送消息到客户端
     */
    public static function ev_send($socket_id, $string) {
        $length = strlen ( $string );
        $con = self::$connections [$socket_id];
        for($written = 0; $written < $length; $written += @$fwrite) {
            $fwrite = fwrite ( $con, substr ( $string, $written ) );
            if ($fwrite === false) {
                return $written;
            }
        }
        return $written;
    }
    public static function ev_sendall($string) {
        print_r ( self::$connections );
        foreach ( self::$connections as $k => $v ) {
            var_dump ( self::ev_send ( $v, $string ) );
        }
    }
    /**
     * 关闭客户端
     */
    public static function close($socket_id = null, $event = null) {
        if ($event) {
            event_del ( $event );
            event_free ( $event );
        }
        if (! $socket_id) {
            $socket_id = self::$id;
        }
        $connection = self::$connections [$socket_id];
        stream_socket_shutdown ( $connection, STREAM_SHUT_RDWR );
        fclose ( self::$connections [$socket_id] );
        unset ( self::$buffers [$socket_id], self::$connections [$socket_id] );
    }
    /**
     * 开启进程数
     */
    public static function sw_spawn($num) {
        for($i = 0; $i < $num; $i ++) {
            $pid = pcntl_fork ();
            if (! $pid) {
                break;
            } else {
                self::$pids [] = $pid;
            }
        }
    }
    public static function getCIp($id = null) {
        if (! $id) {
            $id = self::$id;
        }
        $connection = self::$connections [$id];
        $ip = stream_socket_get_name ( $connection, true );
        return $ip;
    }
}
new epoll ( 8080, 1 ); 